/**
 * 
 */
package edu.jhu.tcj.purfuit;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.swing.JOptionPane;

import edu.jhu.tcj.purfuit.Turn.TurnState;
import edu.jhu.tcj.purfuit.utils.GameFile;

/**
 * @author Bobby
 * @author Brad Gabrielse
 */
public class Game {
	
	/** Unique identifier */
	private int gameID;
	/** Game description */
	private String description;
	/** Game players */
	private List<Player> players = new ArrayList<Player>();
	/** Game board */
	private Board board;
	/** Die for the game */
	private Die die;
	/** Current Turn */
	private Turn turn;
	/** Winner of the game */
	private Player winner;
	/** Whether the game is over */
	private boolean gameOver;
	/** Saves / loads the game */
	private GameFile gameFile;
	/** Property Change Support */
	private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
	
	/**
	 * Default constructor
	 * @param players
	 * @param categories
	 */
	public Game(Player[] players, Category[] categories) {
		
		//Create new Board
		this.board = new Board(categories);
		
		while (this.players.size() < players.length) {
			int index = (int)Math.floor(Math.random()*players.length);
			Player player = players[index];
			if (!this.players.contains(player)) {
				this.players.add(player);
				player.setSpace(board.getCenterSpace());
			}
		}
		
		//Create Die
		die = new Die(6);
		
		//Create First Turn
		turn = new Turn(this.players.get(0), this, pcs);
		
		addPropertyChangeListener(Turn.TURN_STATE_UPDATE, new PropertyChangeListener() {
			
			@Override
			public void propertyChange(PropertyChangeEvent arg0) {
				Object newValue = arg0.getNewValue();
				if (newValue instanceof TurnState) {
					TurnState turnState = (TurnState)newValue;
					if (TurnState.TurnOver.equals(turnState)) {
						changeTurn();
					}
				}
			}
		});
	}
	
	public void saveGame() {
		gameFile = new GameFile();
		try {
			gameFile.saveGame(this);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(null, "Unable to save game");
		} catch (IOException e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(null, "Unable to save game");
		}
	}
	
	private Player getNextPlayer() {
		int indexOf = players.indexOf(turn.getPlayer());
		Player newPlayer = players.get((indexOf+1)%players.size());
		return newPlayer;
	}
	
	public Turn getTurn() {
		return this.turn;
	}
	
	private void changeTurn(){
		this.turn = new Turn(getNextPlayer(), this, pcs);
	}
	
	public int getGameID() {
		return gameID;
	}
	public void setGameID(int gameID) {
		this.gameID = gameID;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public List<Player> getPlayers() {
		return players;
	}
	public void setPlayers(List<Player> players) {
		this.players = players;
	}
	
	public Board getBoard() {
		return board;
	}
	
	public void setBoard(Board board) {
		this.board = board;
	}
	
	public int rollDie() {
		return die.roll();
	}
	
	public Question getCurrentQuestion() {
		return turn.getCurrentQuestion();
	}
	
	public Player getPlayersTurn() {
		return turn.getPlayer();
	}
	
	public Collection<Space> getPossibleMoves() {
		return turn.getAvailableSpaces();
	}
	
	public Player getWinner() {
		if (isGameOver()) {
			return winner;
		}
		return null;
	}
	
	public boolean isGameOver() {
		return gameOver;
	}
	
	public void setGameOver(boolean gameOver) {
		this.gameOver = gameOver;
	}

	public void endGame() {
		gameOver = true;
		this.winner = turn.getPlayer();
	}
	
	public TurnState getTurnState() {
		return getTurn().getTurnState();
	}
	
	public void addPropertyChangeListener(PropertyChangeListener listener) {
		pcs.addPropertyChangeListener(listener);
	}
	
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
		pcs.addPropertyChangeListener(propertyName, listener);
	}

	public Die getDie() {
		return die;
	}

	/**
	 * @param turn the turn to set
	 */
	public void setTurn(Turn turn) {
		this.turn = turn;
	}
	
}
